package com.hzhanghuan.recyclerview;

import android.content.Context;
import android.support.annotation.IntDef;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
 * 扩展了RecyclerView的一些功能
 * Created by Administrator on 2016/4/11.
 */
public class SuperRecyclerView extends RecyclerView {

    /**
     * Normal list that does not indicate choices
     */
    public static final int CHOICE_MODE_NONE = 0;

    /**
     * The list allows up to one choice
     */
    public static final int CHOICE_MODE_SINGLE = 1;

    /**
     * The list allows multiple choices
     */
    public static final int CHOICE_MODE_MULTIPLE = 2;


    @IntDef({SuperRecyclerView.CHOICE_MODE_NONE, SuperRecyclerView.CHOICE_MODE_SINGLE, SuperRecyclerView.CHOICE_MODE_MULTIPLE})
    public @interface MODE {
    }


    /**
     * 选择模式
     */
    @MODE
    int mChoiceMode = CHOICE_MODE_NONE;

    /**
     * 多选记录
     */
    List<Integer> mCheckedPosition = new ArrayList<>();

    /**
     * ActionMode的实例
     */
    ActionMode mChoiceActionMode;

    /**
     * 多选回调的包装
     */
    MultiChoiceModeWrapper mMultiChoiceModeCallback;


    public SuperRecyclerView(Context context) {
        super(context);
    }


    public SuperRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public SuperRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    /**
     * 设置多选ActionMode的callback
     *
     * @param callback
     */
    public void setMultiChoiceModeCallback(MultiChoiceModeCallback callback) {
        if (mMultiChoiceModeCallback == null) {
            mMultiChoiceModeCallback = new MultiChoiceModeWrapper(callback);
        } else {
            mMultiChoiceModeCallback.setWrapped(callback);
        }
    }


    /**
     * 设置选择模式,默认情况下是{@link #CHOICE_MODE_NONE}
     * ,当前可用的是多选({@link #CHOICE_MODE_MULTIPLE})和单选模式({@link #CHOICE_MODE_SINGLE})
     *
     * @param mode 选择模式
     */
    public void setChoiceMode(@MODE int mode) {
        this.mChoiceMode = mode;
    }


    /**
     * 设置指定位置的选择状态
     *
     * @param position
     * @param checked
     */
    public void setItemChecked(int position, boolean checked) {
        //默认状态不支持
        if (mChoiceMode == CHOICE_MODE_NONE) {
            return;
        }
        //多选
        if (checked && mChoiceMode == CHOICE_MODE_MULTIPLE && mChoiceActionMode == null) {
            if (mMultiChoiceModeCallback == null) {
                throw new IllegalStateException("must call setMultiChoiceModeCallback !!!");
            }
            mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
        }
        if (mChoiceActionMode != null) {
            final long id = getAdapter().getItemId(position);
            mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
                    position, id, checked);
            if (checked) {
                saveCheckPosition(position);
            } else {
                removeCheckPosition(position);
            }
        }

    }


    /**
     * 判断指定位置的item是否被选中
     *
     * @param position
     * @return
     */
    public boolean isItemCheck(int position) {
        switch (mChoiceMode) {
            case CHOICE_MODE_MULTIPLE: {
                return mCheckedPosition.contains(position);
            }
            case CHOICE_MODE_NONE: {
                return false;
            }
            case CHOICE_MODE_SINGLE: {
                //预留
                return false;
            }
            default:
                return false;
        }
    }


    /**
     * 获取被选中的item的数量
     *
     * @return
     */
    public int getCheckedCount() {
        switch (mChoiceMode) {
            case CHOICE_MODE_MULTIPLE: {
                return mCheckedPosition.size();
            }
            case CHOICE_MODE_NONE: {
                return 0;
            }
            case CHOICE_MODE_SINGLE: {
                //预留
                return 1;
            }
            default:
                return 0;
        }
    }


    /**
     * 清除以前设置的所有选择
     */
    public void clearChoices() {
        if (mMultiChoiceModeCallback == null) {
            throw new IllegalStateException("must call setMultiChoiceModeCallback !!!");
        }
        //清除CHOICE_MODE_MULTIPLE的选择
        mCheckedPosition.clear();
        if (getAdapter().getItemCount() != 0) {
            LayoutManager layoutManager = getLayoutManager();
            int childCount = layoutManager.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = layoutManager.getChildAt(i);
                ViewHolder viewHolder = getChildViewHolder(child);
                if (viewHolder != null && !viewHolder.isRecyclable() && mChoiceActionMode != null) {
                    mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode, viewHolder.getAdapterPosition(), viewHolder.getItemId(), false);
                }
            }
        }

        //清除CHOICE_MODE_SINGLE的选择
    }


    private void saveCheckPosition(int position) {
        if (!mCheckedPosition.contains(position)) {
            mCheckedPosition.add(position);
        }
    }


    private void removeCheckPosition(int position) {
        if (mCheckedPosition.contains(position)) {
            Integer integer = position;
            mCheckedPosition.remove(integer);
        }
    }


    @Override
    public void onChildAttachedToWindow(View child) {
        super.onChildAttachedToWindow(child);
        if (mChoiceMode == CHOICE_MODE_MULTIPLE && mMultiChoiceModeCallback != null && mChoiceActionMode != null) {
            ViewHolder viewHolder = getChildViewHolder(child);
            mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode, viewHolder.getAdapterPosition(), viewHolder.getItemId(), false);
        }
    }


    @Override
    public void onChildDetachedFromWindow(View child) {
        super.onChildDetachedFromWindow(child);
        if (mChoiceMode == CHOICE_MODE_MULTIPLE && mMultiChoiceModeCallback != null && mChoiceActionMode != null) {
            ViewHolder viewHolder = getChildViewHolder(child);
            if (mCheckedPosition.contains(viewHolder.getAdapterPosition())) {
                Integer pos = viewHolder.getAdapterPosition();
                mCheckedPosition.remove(pos);
            }
        }


    }


    /**
     * 多选模式的ActionMode的回调接口
     */
    public interface MultiChoiceModeCallback extends ActionMode.Callback {

        /**
         * 这个方法在某个item被选中后被调用,在这处理view的状态
         *
         * @param mode
         * @param position
         * @param id
         * @param checked
         */
        void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked);

    }


    class MultiChoiceModeWrapper extends AdapterDataObserver implements MultiChoiceModeCallback {


        private MultiChoiceModeCallback mWrapped;


        public MultiChoiceModeWrapper(MultiChoiceModeCallback mWrapped) {
            this.mWrapped = mWrapped;
        }


        public void setWrapped(MultiChoiceModeCallback wrapped) {
            this.mWrapped = wrapped;
        }


        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            registerAdapterDataObserver();
            return mWrapped.onCreateActionMode(mode, menu);
        }


        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return mWrapped.onPrepareActionMode(mode, menu);
        }


        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            boolean hasClicked = mWrapped.onActionItemClicked(mode, item);
            if (hasClicked && getAdapter().getItemCount() == 0 && mChoiceActionMode != null) {
                mChoiceActionMode.finish();
            }
            return hasClicked;
        }


        @Override
        public void onDestroyActionMode(ActionMode mode) {
            clearChoices();
            mChoiceActionMode = null;
            mWrapped.onDestroyActionMode(mode);
            unregisterAdapterDataObserver();
        }


        @Override
        public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
            mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
        }


        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            super.onItemRangeMoved(fromPosition, toPosition, itemCount);
        }


        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);
        }


        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            for (int i = 0; i < itemCount; i++) {
                ViewHolder viewHolder = findViewHolderForAdapterPosition(positionStart);
                mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode, viewHolder.getAdapterPosition(), viewHolder.getItemId(), false);
            }
            syncCheckStatus(positionStart, itemCount);
        }


        private void syncCheckStatus(int positionStart, int itemCount) {
            if (itemCount <= 0) {
                return;
            }
            List<Integer> newCheckStatus = new ArrayList<>();
            for (int i = 0; i < getCheckedCount(); i++) {
                int checkPosition = mCheckedPosition.get(i);
                if (checkPosition < positionStart) {
                    break;
                } else if (checkPosition <= (positionStart + itemCount - 1)) {
                    break;
                } else {
                    newCheckStatus.add(checkPosition - itemCount);
                }
            }
            mCheckedPosition.clear();
            mCheckedPosition.addAll(newCheckStatus);


        }


        private void registerAdapterDataObserver() {
            getAdapter().registerAdapterDataObserver(this);
        }


        private void unregisterAdapterDataObserver() {
            getAdapter().unregisterAdapterDataObserver(this);
        }


    }

}
